/******************************************************************************\
*                                                                              *
*     File: TestSet.h                                                          *
*                                                                              *
*   Author: Douwe A. van Twillert                                              *
*  Purpose: A framework for unit testing                                       *
*  Version: 1.0      TWI 20070311                                              *
*           - Initial version                                                  *
*  Version: 1.0.1    AKK 20070322                                              *
*           - TestSet_output_not_reached_failed(...) added                     *
*  Version: 1.0.2    TWI 20070323                                              *
*           - Changed all tabs to spaces                                       *
*           - Made versioning comments consistent                              *
*  Version: 1.1      TWI 20080218                                              *
*           - Changed the header file for clear printing                       *
*                                                                              *
\******************************************************************************/

#ifndef __TEST_SET
#define __TEST_SET

/*
 *  System Includes
 */
#include <signal.h>  // for SIGABRT
#include<stdlib.h>   // for exit

#include "TestSet_output.h"

/*
 *  Module defines
 */
typedef enum 
{
   TEST_CASE_MAGIC = 0xA7A7A7A7,
   TEST_SET_MAGIC =  0x7A7A7A7A,
   TEST_SET_DESTRUCTED = 0x96969696
} TestSet_magic_enum;

static const bool OK = true;

#define TEST_SET(set_name)                                         \
            test_set test_set__ ## set_name = {                    \
                   TEST_SET_MAGIC,                                 \
                   #set_name,                                      \
                   0,                                              \
                   0,                                              \
                   0,                                              \
                   0,                                              \
                   0,                                              \
                   0,                                              \
                   0,                                              \
                   TestSet_add_set( & test_set__ ## set_name )     \
            };

#define TEST(test)                                                 \
            bool test();                                           \
            TEST_SET_ADD(test)                                     \
            bool test()                                            \
            {                                                      \
                bool result = OK;
                
#define END_TEST                                                   \
                return result;                                     \
            }

#define TEST_SET_ADD(test)                                         \
       static TestCase test_case ## test = {                       \
          TEST_CASE_MAGIC,                                         \
          #test,                                                   \
          (test),                                                  \
          TestSet_add_test_case( & test_case ## test )             \
       };

#define VERIFY(expression)                                         \
    if ( result == OK && !(expression) )                           \
    {                                                              \
       result = !OK;                                               \
       TestSet_output_verification_failed(__FILE__, __LINE__,      \
                                          #expression);            \
    }

#define EXPECT_NOT_REACHED                                         \
    if ( result == OK )                                            \
    {                                                              \
       result = !OK;                                               \
       TestSet_output_not_reached_failed(__FILE__, __LINE__);      \
    }

#define EXPECT_SYSTEM_ASSERTION_FAILED                             \
    TestSet_output_expect_assertion_failed();                      \
    TestSet_expect_signal(SIGABRT);

#define EXPECT_SIGNAL(signal)                                      \
    TestSet_output_expect_signal(signal);                          \
    TestSet_expect_signal(signal);

#define CHECK VERIFY


/*
 *  Module typedefinitions
 */
typedef bool (*TestSet_test)(void);

typedef struct test_case
{
   TestSet_magic_enum magic;
   const char*        name;
   TestSet_test       test;
   test_case*         next;
} TestCase;

typedef struct test_set
{
   TestSet_magic_enum magic;
   const char* name;
   int         passed;
   int         failed;
   int         total;
   int         nr_of_testcases;
   TestCase*   head;
   TestCase*   tail;
   TestCase*   current;
   test_set*   next;
} TestSet;

/*
 *  Module Exported Global data
 */

/*
 *  Module Exported functions
 */
extern TestSet* TestSet_add_set( TestSet* test_set );
extern TestCase* TestSet_add_test_case( TestCase* test_case );

extern void TestSet_expect_signal(int a_signal);
extern int TestSet_execute();

#endif  // __TEST_SET
